# api_tests/tests.py
from rest_framework.test import APITestCase
from rest_framework import status
from django.urls import reverse  # 推荐使用reverse生成URL，避免硬编码
from users.models import User
from files.models import File


class FileAPITest(APITestCase):
    def setUp(self):
        # 初始化测试用户
        self.user = User.objects.create_user(username='testuser', password='123456', role='user')
        self.admin = User.objects.create_user(username='admin', password='123456', role='admin')
        # 定义API URL（推荐使用reverse，需在urls.py中给视图命名）
        self.file_url = reverse('file-list')  # 假设URL名称为'file-list'

    def test_user_file_upload_success(self):
        """测试普通用户成功上传文件"""
        self.client.force_authenticate(user=self.user)  # 认证为普通用户
        with open('test.png', 'rb') as f:  # 打开测试文件
            data = {'name': 'test_file', 'file': f}
            response = self.client.post(self.file_url, data, format='multipart')

        # 验证响应状态码（201表示创建成功）
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        # 验证数据库中新增了一条记录
        self.assertEqual(File.objects.count(), 1)
        # 验证返回数据中的文件名正确
        self.assertEqual(response.data['name'], 'test_file')

    def test_unauthenticated_user_upload_failed(self):
        """测试未认证用户上传文件失败（401未授权）"""
        # 不进行认证
        with open('test.png', 'rb') as f:
            data = {'name': 'test_file', 'file': f}
            response = self.client.post(self.file_url, data, format='multipart')

        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
        self.assertEqual(File.objects.count(), 0)  # 数据库无新增记录

    def test_file_upload_missing_parameter(self):
        """测试缺少必填参数（如name）时上传失败（400错误）"""
        self.client.force_authenticate(user=self.user)
        with open('test.png', 'rb') as f:
            data = {'file': f}  # 缺少name参数
            response = self.client.post(self.file_url, data, format='multipart')

        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_admin_can_delete_file(self):
        """测试管理员可以删除文件（普通用户可能无权限）"""
        # 先创建一个文件
        self.client.force_authenticate(user=self.user)
        with open('test.png', 'rb') as f:
            response = self.client.post(self.file_url, {'name': 'test', 'file': f}, format='multipart')
        file_id = response.data['id']  # 获取创建的文件ID

        # 切换为管理员身份删除文件
        self.client.force_authenticate(user=self.admin)
        delete_response = self.client.delete(f'{self.file_url}{file_id}/')  # 假设删除URL为/file/{id}/
        self.assertEqual(delete_response.status_code, status.HTTP_204_NO_CONTENT)
        self.assertEqual(File.objects.count(), 0)  # 数据库中文件已删除

    def test_user_cannot_delete_file(self):
        """测试普通用户无法删除文件（403禁止）"""
        # 先创建一个文件
        self.client.force_authenticate(user=self.user)
        with open('test.png', 'rb') as f:
            response = self.client.post(self.file_url, {'name': 'test', 'file': f}, format='multipart')
        file_id = response.data['id']

        # 用普通用户身份尝试删除
        delete_response = self.client.delete(f'{self.file_url}{file_id}/')
        self.assertEqual(delete_response.status_code, status.HTTP_403_FORBIDDEN)
        self.assertEqual(File.objects.count(), 1)  # 文件未被删除

    # 在FileAPITest类中添加以下测试方法

    def test_user_can_only_see_own_files(self):
        """测试普通用户只能查看自己上传的文件"""
        # 普通用户上传文件
        self.client.force_authenticate(user=self.user)
        with open('test.png', 'rb') as f:
            self.client.post(self.file_url, {'name': 'user_file', 'file': f}, format='multipart')

        # 管理员上传文件
        self.client.force_authenticate(user=self.admin)
        with open('test.png', 'rb') as f:
            self.client.post(self.file_url, {'name': 'admin_file', 'file': f}, format='multipart')

        # 切换回普通用户查看列表
        self.client.force_authenticate(user=self.user)
        response = self.client.get(self.file_url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        # 普通用户应只能看到自己的1个文件
        self.assertEqual(len(response.data), 1)
        self.assertEqual(response.data[0]['name'], 'user_file')

    def test_admin_can_see_all_files(self):
        """测试管理员可以查看所有文件"""
        # 普通用户上传文件
        self.client.force_authenticate(user=self.user)
        with open('test.png', 'rb') as f:
            self.client.post(self.file_url, {'name': 'user_file', 'file': f}, format='multipart')

        # 管理员上传文件
        self.client.force_authenticate(user=self.admin)
        with open('test.png', 'rb') as f:
            self.client.post(self.file_url, {'name': 'admin_file', 'file': f}, format='multipart')

        # 管理员查看列表
        response = self.client.get(self.file_url)
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        # 管理员应看到所有2个文件
        self.assertEqual(len(response.data), 2)

    def test_file_upload_invalid_type(self):
        """测试上传不支持的文件类型（如.txt）是否失败"""
        self.client.force_authenticate(user=self.user)
        # 创建一个临时txt文件
        with open('test.txt', 'w') as f:
            f.write('test content')
        with open('test.txt', 'rb') as f:
            data = {'name': 'invalid_file', 'file': f}
            response = self.client.post(self.file_url, data, format='multipart')

        # 假设业务要求只允许图片，此处应返回400错误
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)